package com.unlcn.ils.sales.backend.security;


import cn.huiyunche.commons.enums.SigninErrorEnum;
import cn.huiyunche.commons.utils.AppUtil;
import com.alibaba.fastjson.JSONObject;
import com.unlcn.ils.sales.backend.security.domains.UserSecurityVO;
import com.unlcn.ils.sales.backend.util.JdbcTemplateUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Map;

/**
 * jwt认证过滤.
 * <p>
 * 当header中包含token时，通过本filter还原用户信息，供后续通过认证使用.
 *
 * @author qichao
 */
public class JwtAuthenicationFilter extends GenericFilterBean {

    public static final String HEADER_AUTHORIZATION = "Authorization";

    public static final String PREFIX_AUTHORIZATION = "Bearer ";

    private String secureKey = null;

    public JwtAuthenicationFilter(String secureKey) {
        this.secureKey = secureKey;
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest servletRequest = (HttpServletRequest) request;
        String token = servletRequest.getHeader(JwtAuthenicationFilter.HEADER_AUTHORIZATION);
        if ((token == null) || !token.startsWith(JwtAuthenicationFilter.PREFIX_AUTHORIZATION)) {
            chain.doFilter(servletRequest, response);
            return;
        }
        String jwt = token.substring(7);
        try {
            UserSecurityVO user = JwtUtils.parseToken(jwt,this.getSecureKey());
            if (user != null && this.isExistedAccount(user)) {
                Authentication authentication = this.createAuthentication(user);
                SecurityContextHolder.getContext().setAuthentication(authentication);
                chain.doFilter(servletRequest, response);
                SecurityContextHolder.getContext().setAuthentication(null);
            } else {
                AppUtil.responseErrorJson(response, SigninErrorEnum.UserUnableInvalidError);
            }
        } catch (Exception e) {
            e.printStackTrace();
            if (e.getCause().getMessage().startsWith("Form too large")) {
                AppUtil.responseErrorJson(response, SigninErrorEnum.FormTooLarge);
            }
            AppUtil.responseErrorJson(response, SigninErrorEnum.AuthenticationInvalidError);
        }
    }

    private Authentication createAuthentication(UserSecurityVO user) {
        return new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
    }

    public String getSecureKey() {
        return this.secureKey;
    }

    /**
     * 判断用户是否可用
     *
     * @param user 用户
     * @return 是否可用
     */
    private boolean isExistedAccount(UserSecurityVO user) {
        String username = user.getUsername();
        if (StringUtils.isNotBlank(username)) {
            String sql = "select count(1) as count from sale_user where login_name ='" + username +"'";
            Map<String, Object> map = JdbcTemplateUtils.getJdbcTemplate().queryForMap(sql);
            JSONObject json = JSONObject.parseObject(JSONObject.toJSONString(map));
            if (null != json && json.getIntValue("count") == 1) {
                return true;
            }
        }
        return false;
    }

}
